package com.zhejiangzhengyuan.municipal_common.utils;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zhejiangzhengyuan.municipal_common.annotation.AuthorizationLess;
import com.zhejiangzhengyuan.municipal_common.entity.Action;
import com.zhejiangzhengyuan.municipal_common.entity.BusinessLog;
import com.zhejiangzhengyuan.municipal_common.entity.Subject;
import com.zhejiangzhengyuan.municipal_common.mapper.ActionMapper;
import com.zhejiangzhengyuan.municipal_common.service.ActionService;
import com.zhejiangzhengyuan.municipal_common.service.BusinessLogService;
import com.zhejiangzhengyuan.municipal_common.service.SubjectService;
import com.zhejiangzhengyuan.municipal_common.utils.httpUtils.ForbiddenException;
import com.zhejiangzhengyuan.municipal_common.utils.httpUtils.NotFoundException;
import com.zhejiangzhengyuan.municipal_common.utils.httpUtils.ServerErrorException;
import com.zhejiangzhengyuan.municipal_common.utils.httpUtils.UnauthorizedException;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;
import java.util.regex.Pattern;

import static com.zhejiangzhengyuan.municipal_common.utils.JwtUtil.HEADER_STRING;

/**
 * @author lin_ju
 * @create on 2019/11/26 JWT拦截器认证身份
 */
@Component
@Slf4j
public class JwtFilter implements HandlerInterceptor {

  @Autowired SubjectService subjectService;
  @Autowired ActionService actionService;
  @Autowired BusinessLogService businessLogService;
  @Autowired ActionMapper actionMapper;
  @Autowired private JwtUtil jwtUtil;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
    // 静态资源请求默认通过
    if(handler instanceof ResourceHttpRequestHandler ){
      return  true;
    }
    if (handler instanceof HandlerMethod) {
      HandlerMethod handlerMethod = (HandlerMethod) handler;
      Method method = handlerMethod.getMethod();
      String uri = request.getRequestURI();

      // 若访问不存在路径 返回其404
      if (Strings.isBlank(uri) || uri.equals("/error")) {
        // 进入此处说明请求路径不存在或服务器端出现异常需区分出来
        if (response.getStatus() == 404) {
          throw new NotFoundException();
          //                case 500:
          //                    throw new ServerErrorException();
        }
        throw new ServerErrorException();
      }

      AuthorizationLess less = method.getAnnotation(AuthorizationLess.class);
      // AuthorizationLess为null 则表示使用鉴权 没有则跳过
      if (!Objects.nonNull(less)) {
        // 获取token的id 判断其是否有访问url的权限
        String token = request.getHeader(HEADER_STRING);
        // 占位符
        String placeholder = "{id}";
        /// information/findDeviceById/{id}/action/{id} 考虑到如上极端情况生成
        String[] uris = uri.split("/");
        Pattern pattern = Pattern.compile("[0-9]*");
        for (String uri_item : uris) {
          // 判断字符是否是数字，当前模式下纯数字即可代表其为PathParam
          if (!Strings.isBlank(uri_item) && pattern.matcher(uri_item).matches()) {
            uri = uri.replace(uri_item, placeholder);
          }
        }
        if (token != null) {
          Claims claims = JwtUtil.parseJWT(token);
          Long id = Long.valueOf(String.valueOf(claims.get("id")));
          if (actionService.findBySubjectIdByUrlAction(id, uri).isEmpty()) {
            throw new ForbiddenException();
          } else {
            // 目前根据角色关联行为表进行鉴权 后期加入权限表进行set去重后鉴权
            List<String> urls = actionMapper.selectUrlBySubjectId(id);
            for (String s : urls) {
              if (s.equals(uri)) {
                // 存取用户操作日志
                QueryWrapper<Action> actionQueryWrapper = new QueryWrapper<>();
                actionQueryWrapper.eq("pattern_url", uri);
                Action action = actionService.getOne(actionQueryWrapper);
                Subject subject = subjectService.getById(id);
                BusinessLog businessLog = new BusinessLog();
                businessLog
                        .setAction(ConstantUtil.getActionMethod(request.getMethod()))
                        .setModule(action.getModuleName())
                        .setCreateTime(DateFormatUtil.timeFormat(System.currentTimeMillis()))
                        .setUrl(uri)
                        .setSubjectName(subject.getSubjectName());
                businessLogService.save(businessLog);
                return true;
              }
            }
          }
        } else {
          // api需要携带token
          throw new UnauthorizedException();
        }
      }
    }
    return true;
  }

  @Override
  public void postHandle(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      Object o,
      ModelAndView modelAndView)
      throws Exception {}

  @Override
  public void afterCompletion(
      HttpServletRequest httpServletRequest,
      HttpServletResponse httpServletResponse,
      Object o,
      Exception e)
      throws Exception {}
}
